/* -----------------
* brief
* 1. this is code gen by tools
* 2. array like [a,b,c] after each field, define the ui html tag in view,
		a for title,
		b for show or not ,
		c for element html tag , currently suppor : check、radio、select、input、textarea、upload tag
* 3. XXX
*/

package controller

import (
	"errors"
	"fmt"
	"github.com/chanxuehong/wechat/mp/card"
	"github.com/chanxuehong/wechat/mp/menu"
	"github.com/chanxuehong/wechat/mp/message/callback/request"
	"saas_sys_base/common"

	//. "lego_wechat/modules/wechat/models"
	//. "lego_wechat/modules/wechat/service"
	mchcore "github.com/chanxuehong/wechat/mch/core"
	"github.com/chanxuehong/wechat/mchv3/corev3"
	"github.com/chanxuehong/wechat/mp/core"
	"github.com/chanxuehong/wechat/mp/jssdk"
	configService "saas_sys_base/modules/config/service"
)

//原来想把WxServer放在/modules/wechat目录下的，但是一些实现细节中涉及到两个文件的互相引用，所以暂时放wechat/controller里
type WxServer struct {
	//service  WechatSdkService
	appConfigService configService.AppConfigService
}

var _vcWxServer *WxServer

func init() {
	vc := new(WxServer)
	_vcWxServer = vc
	_ctrlList = append(_ctrlList, vc)

	_wxServerMap = make(map[string]*WxCoreServer)

	//t := new(WechatSdkCallbackCtrl)  // TODO这种方式有点不好，先这样
	t := _vcWxServer
	appConfigList := t.appConfigService.GetAllAppConfig()

	/*取消将系统配置文件加入加载appconfig的逻辑  sysConfig := t.appConfigService.GetSysConfig() //这里补一脚，把sys的配置加到里面，一起把sys配置对应的wx server也起起来
	appConfigList = append(appConfigList, sysConfig)*/

	for _, v := range appConfigList {
		//MakeWxServerToMap(v, WX_SERVER_TYPE_MP)
		MakeWxServerToMap(v, WX_SERVER_TYPE_WEAPP_MCH)
		MakeWxServerToMap(v, WX_SERVER_TYPE_WEAPP_MCHv3)
	}

	return
}

func (vc *WxServer) CtrlInfo() string {
	return "WxServer"
}

func (vc *WxServer) RoutInit() {
	//lego.POST("/wx_callback", wxCallbackHandlerEx, lego.LEGO_SESSION_TYPE_WEB, false)
}

/*
var (
	// 下面两个变量不一定非要作为全局变量, 根据自己的场景来选择.
	msgHandler core.Handler
	msgServer  *core.Server
)
*/

var _wxServerMap map[string]*WxCoreServer
var _wxCheckServerMap map[string]*common.AppConfig //用于检测是否有重复的公众号配置
type WxCoreServer struct { //这里这么多指针，后续优化为interface{},不过呢，这种形式可读性比较强
	wxServer          *core.Server
	wxMchServer       *mchcore.Server
    wxMchv3Server     *corev3.Server
	cardTicketServer  jssdk.CardTicketServer
	ticketServer      jssdk.TicketServer
	serverType        WxServerType
	appconfigforcheck *common.AppConfig //这个只用于检测配置重复，不可取出来作为其它用途,并且在这里只有wechat部分的配置有意义
}

func NewWeChatMpServer(oriId, wxAppId, token, base64AESKey string, errorHandler core.ErrorHandler) (srv *core.Server) {
	mux := core.NewServeMux()
	mux.DefaultMsgHandleFunc(defaultMsgHandler)
	mux.DefaultEventHandleFunc(defaultEventHandler)
	mux.MsgHandleFunc(request.MsgTypeText, textMsgHandler)
	mux.EventHandleFunc(menu.EventTypeClick, menuClickEventHandler)

	//Card event:
	cardCallBackCtrl := GetInstanceWechatSdkCardCallbackCtrl()
	mux.EventHandleFunc(card.EventTypeCardPassCheck, cardCallBackCtrl.CardPassCheckEventHandler)
	mux.EventHandleFunc(card.EventTypeCardNotPassCheck, cardCallBackCtrl.CardNotPassCheckEventHandler)
	mux.EventHandleFunc(card.EventTypeUserGetCard, cardCallBackCtrl.CardGetCardEventHandler)
	mux.EventHandleFunc(card.EventTypeUserDelCard, cardCallBackCtrl.UserDelCardEventHandler)
	mux.EventHandleFunc(card.EventTypeUserConsumeCard, cardCallBackCtrl.UserConsumeCardEventHandler)
	mux.EventHandleFunc(card.EventTypeUserViewCard, cardCallBackCtrl.UserViewCardEventHandler)
	mux.EventHandleFunc(card.EventTypeUserEnterSessionFromCard, cardCallBackCtrl.UserEnterSessionEventHandler)
	mux.EventHandleFunc(card.EventTypeSubmitMemberCardUserInfo, cardCallBackCtrl.SubmitMemberCardUserInfoEventHandler)

	mux.EventHandleFunc(card.EventTypeCardMerchantCheckResult, cardCallBackCtrl.CardMerchantCheckResultEventHandler)

	/*mux.EventHandleFunc(card.EventTypeQualificationVerfiySuccess, cardCallBackCtrl.QualificationVerfiySuccessEventHandler)
	mux.EventHandleFunc(card.EventTypeQualificationVerfiyFail, cardCallBackCtrl.QualificationVerfiyFailEventHandler)
	mux.EventHandleFunc(card.EventTypeNamingVerfiyFail, cardCallBackCtrl.NamingVerfiyFailEventHandler)
	mux.EventHandleFunc(card.EventTypeAnnualRenew, cardCallBackCtrl.AnnualRenewEventHandler)
	mux.EventHandleFunc(card.EventTypeVerifyExpired, cardCallBackCtrl.VerifyExpiredEventHandler)*/

	msgHandler := mux
	msgServer := core.NewServer(oriId, wxAppId, token, base64AESKey, msgHandler, nil)
	return msgServer
}

func NewWxMchServer(appId, mchId, apiKey string) (srv *mchcore.Server) {
    return mchcore.NewServer(appId, mchId, apiKey, &_WxPayActionCtrl, nil)
}

func GetMpServerByWeappId(weappid string) *core.Server {
	server, ok := _wxServerMap[weappid]
	if !ok {
		return nil
	}

	return server.wxServer
}

func GetMchServerByAppidAndMchId(appid string, mchId string) *mchcore.Server {
    key := KeyOfMch(appid, mchId, WX_SERVER_TYPE_WEAPP_MCH) //这里填WX_SERVER_TYPE_WEAPP_MCH或WX_SERVER_TYPE_MP_MCH都可以
	server := _wxServerMap[key].wxMchServer
	return server
}

func GetMchv3ServerByAppidAndMchId(appid string, mchId string) *corev3.Server {
	key := KeyOfMch(appid, mchId, WX_SERVER_TYPE_WEAPP_MCHv3) //这里填WX_SERVER_TYPE_WEAPP_MCHv3或WX_SERVER_TYPE_MP_MCHv3都可以
	server := _wxServerMap[key].wxMchv3Server
	return server
}

type WxServerType uint

const (
	WX_SERVER_TYPE_MP    WxServerType = 0
	WX_SERVER_TYPE_WEAPP WxServerType = 1
	WX_SERVER_TYPE_MP_MCH   WxServerType = 3
	WX_SERVER_TYPE_WEAPP_MCH   WxServerType = 4
	WX_SERVER_TYPE_MP_MCHv3   WxServerType = 5
	WX_SERVER_TYPE_WEAPP_MCHv3   WxServerType = 6
)

func KeyOfMch(appid string, mchid string, serverType WxServerType) string {
	key := fmt.Sprintf("%s_%s", appid, mchid)
	if serverType == WX_SERVER_TYPE_MP_MCHv3 || serverType == WX_SERVER_TYPE_WEAPP_MCHv3 {
		key = key + "_v3"
	}
	return key
}

func MakeWxServerToMap(appconfig *common.AppConfig, serverType WxServerType) error {
	wechatConfig := appconfig.App_Config_Data.Wechat
	var appid string
	var apptoken string
	var appaeskey string

	var mchid string //用于商户号

	var keyOfMap string //一般是以appid作为map的key
	if serverType == WX_SERVER_TYPE_MP {
		appid = wechatConfig.WX_MP_APPID
		apptoken = wechatConfig.WX_MP_TOKEN
		appaeskey = wechatConfig.WX_MP_ENCODED_AESKey
		keyOfMap = appid
	} else if serverType == WX_SERVER_TYPE_WEAPP {
		//暂时不支持weapp
		errmsg := fmt.Sprintf("panic: not support wx client type <%d>", serverType)
		panic(errmsg)
		return errors.New(errmsg)
	} else if serverType == WX_SERVER_TYPE_MP_MCH || serverType == WX_SERVER_TYPE_MP_MCHv3{
		appid = wechatConfig.WX_MP_APPID
		mchid = wechatConfig.WX_MERCHANT_ID
		keyOfMap = KeyOfMch(appid, mchid, serverType)
	} else if serverType == WX_SERVER_TYPE_WEAPP_MCH || serverType == WX_SERVER_TYPE_WEAPP_MCHv3 {
		appid = wechatConfig.WX_APPID
		mchid = wechatConfig.WX_MERCHANT_ID
		keyOfMap = KeyOfMch(appid, mchid, serverType)
	}else {
		errmsg := fmt.Sprintf("panic: not support wx client type <%d>", serverType)
		panic(errmsg)
		return errors.New(errmsg)
	}

	if appid == "" { //配置文件中的appid字段未配置
		return nil
	}

	wxserver, ok := _wxServerMap[keyOfMap]
	if ok {
		//如果发现app对应的微信配置存在，则检查是否与前值一致，如果不一致则抛出panic
		//因为微信配置值是必须一致的，这种情况可能是手动输入配置文件时有错误
		//if prevValue.wechatConfig.WX_APPSECRET
		v := appconfig
		v2 := wxserver.appconfigforcheck

		if serverType == WX_SERVER_TYPE_MP {
			if v.App_Config_Data.Wechat.WX_MP_TOKEN != v2.App_Config_Data.Wechat.WX_MP_TOKEN ||
				v.App_Config_Data.Wechat.WX_MP_ENCODED_AESKey != v2.App_Config_Data.Wechat.WX_MP_ENCODED_AESKey {
				panic("there may be mistake in wechat mp config, the same mp config must be same!")
			}
 		} else if serverType == WX_SERVER_TYPE_WEAPP {
			if v.App_Config_Data.Wechat.WX_APPSECRET != v2.App_Config_Data.Wechat.WX_APPSECRET  {
				panic("there may be mistake in wechat weapp config, the same weapp config must be same!")
			}
		} else if serverType == WX_SERVER_TYPE_WEAPP_MCH ||  serverType == WX_SERVER_TYPE_MP_MCH ||
			serverType == WX_SERVER_TYPE_WEAPP_MCHv3 ||  serverType == WX_SERVER_TYPE_MP_MCHv3 {
			//检查mch配置是否一致
			if v.App_Config_Data.Wechat.WX_MERCHANT_ID != v2.App_Config_Data.Wechat.WX_MERCHANT_ID ||
				v.App_Config_Data.Wechat.WX_PAY_KEY != v2.App_Config_Data.Wechat.WX_PAY_KEY {
				panic("there may be mistake in wechat mch config, the same mch config must be same!")
				return errors.New("MakeWxClientToMap failed")
			}
			if serverType == WX_SERVER_TYPE_WEAPP_MCHv3 ||  serverType == WX_SERVER_TYPE_MP_MCHv3 {
				if v.App_Config_Data.Wechat.WX_MCH_V3.WX_MCH_V3_CERT_SERIAL_NO != v2.App_Config_Data.Wechat.WX_MCH_V3.WX_MCH_V3_CERT_SERIAL_NO ||
					v.App_Config_Data.Wechat.WX_MCH_V3.WX_PAY_API_V3_KEY != v2.App_Config_Data.Wechat.WX_MCH_V3.WX_PAY_API_V3_KEY ||
					v.App_Config_Data.Wechat.WX_MCH_V3.WX_MCH_V3_PRI_KEY_CERT != v2.App_Config_Data.Wechat.WX_MCH_V3.WX_MCH_V3_PRI_KEY_CERT  {
					panic("there may be mistake in wechat mchv3 config, the same mchv3 config must be same!")
					return errors.New("MakeWxClientToMap failed")
				}
			}
		}
	}

	_wxServerMap[keyOfMap] = new(WxCoreServer)
	if serverType == WX_SERVER_TYPE_WEAPP || serverType == WX_SERVER_TYPE_MP {
		if _wxServerMap[keyOfMap].wxServer != nil {
			return nil
		}
		_wxServerMap[keyOfMap].wxServer = NewWeChatMpServer("",
			appid,
			apptoken,
			appaeskey, nil)
	} else if  serverType == WX_SERVER_TYPE_WEAPP_MCH ||  serverType == WX_SERVER_TYPE_MP_MCH {
		if _wxServerMap[keyOfMap].wxMchServer != nil {
			return nil
		}
		_wxServerMap[keyOfMap].wxMchServer =NewWxMchServer(appid, mchid, wechatConfig.WX_PAY_KEY)
	} else if  serverType == WX_SERVER_TYPE_WEAPP_MCHv3 ||  serverType == WX_SERVER_TYPE_MP_MCHv3 {
		if _wxServerMap[keyOfMap].wxMchv3Server != nil {
			return nil
		}
		_wxServerMap[keyOfMap].wxMchv3Server = NewWxMchv3Server(appid, mchid,
			                                                    wechatConfig.WX_MCH_V3.WX_MCH_V3_CERT_SERIAL_NO,
			                                                    wechatConfig.WX_MCH_V3.WX_PAY_API_V3_KEY,
			                                                    wechatConfig.WX_MCH_V3.WX_MCH_V3_PRI_KEY_CERT)
	}

	_wxServerMap[keyOfMap].serverType = serverType
	_wxServerMap[keyOfMap].appconfigforcheck = appconfig //将appconfig的内容保存在这个变量里面，方便后续比较
	return nil
}

//支付回调服务器
func NewWeChatMchServer(appId, mchId, apiKey string, errorHandler mchcore.ErrorHandler) (srv *mchcore.Server) {
	msgServer := mchcore.NewServer(appId, mchId, apiKey, nil, nil)
	return msgServer
}
